using System;
using System.Reflection;

namespace UnitTesting.Fixturing
{
	class ArgumentProvider : IArgumentProvider
	{
		readonly IValueProvider _valueProvider;
		readonly IArgumentProvider _argumentProvider;

		internal IArgumentProvider BaseArgumentProvider
		{
			get { return _argumentProvider; }
		}

		internal IValueProvider ValueProvider
		{
			get { return _valueProvider; }
		}

		internal ArgumentProvider(IValueProvider valueProvider, IArgumentProvider argumentProvider)
		{
			_valueProvider = Ensure.IsNotNull(() => valueProvider);
			_argumentProvider = Ensure.IsNotNull(() => argumentProvider);
		}

		public object[] GetArguments(params ParameterInfo[] parameters)
		{
			Ensure.IsNotNull(() => parameters);
			var parameterValues = GetArgumentFromBaseProvider(parameters);
			SetParameterValues(parameters, parameterValues);
			return parameterValues;
		}

		object[] GetArgumentFromBaseProvider(ParameterInfo[] parameters)
		{
			return BaseArgumentProvider.GetArguments(parameters);
		}

		void SetParameterValues(ParameterInfo[] parameters, object[] parameterValues)
		{
			for (int i = 0; i < parameters.Length; i++)
			{
				parameterValues[i] = GetParameValueForNotResovled(parameterValues[i], parameters[i].ParameterType);
			}
		}

		object GetParameValueForNotResovled(object parameterValue, Type parameterType)
		{
			return parameterValue == NotResolved.Value
			       	? GetParameterValueFromProvider(parameterType)
			       	: parameterValue;
		}

		object GetParameterValueFromProvider(Type parameterType)
		{
			return ValueProvider.Create(parameterType);
		}
	}
}